//@author A0105740R
package rightnow.logic;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eaio.uuid.UUID;

import rightnow.storage.Task;
import rightnow.util.DoneComparator;
import rightnow.util.UiOptions;
import rightnow.util.DescriptionComparator;
import rightnow.util.StartEndComparator;
import rightnow.util.PinnedComparator;

/**
 * This class is intended to be used by logic to handle page views
 */
public class ViewList {
	private static final int NO_ELEM_IN_LIST = -1;

	private static final Logger log = LoggerFactory.getLogger(ViewList.class);
	
	private static final String TRACE_REAL_INDEX = "realIndex = %d";
	private static final int INDEX_NOT_FOUND = NO_ELEM_IN_LIST;
	
	private static final int NUM_TASKS_PER_PAGE = UiOptions.TASKS_PER_PAGE;
	
	private List<Task> taskList;
	private List<Task> taskListCurrentPage;
	private int totalPages;
	private int currentPage;
	private ViewListStatus status;
	private SortingMethod sortMethod;
	private String searchTerm;

	public ViewList(List<Task> taskList,
			ViewListStatus status, SortingMethod sortMethod) {
		assert taskList != null;
		this.taskList = taskList;
		this.sortMethod = sortMethod;
		sortList();
		this.totalPages = computeTotalPages();
		this.currentPage = 1;
		this.status = status;
	}
	
	public void setCurrentStatusList(List<Task> taskList) {
		assert taskList != null;
		this.taskList = taskList;
		sortList();
		this.totalPages = computeTotalPages();
		if (currentPage > totalPages) {
			this.currentPage = totalPages;
		}
	}
	
	public void setNewStatusList(List<Task> taskList, ViewListStatus status) {
		assert taskList != null;
		this.taskList = taskList;
		sortList();
		this.totalPages = computeTotalPages();
		this.currentPage = 1;
		this.status = status;
	}

	public void setSortingMethod(SortingMethod sortMethod) {
		this.sortMethod = sortMethod;
		sortList();
		this.currentPage = 1;
	}
	
	private void sortList() {
		switch (sortMethod) {
		case DEFAULT:
			Collections.sort(taskList, new DescriptionComparator());
			Collections.sort(taskList, new StartEndComparator());
			Collections.sort(taskList, new DoneComparator());
			Collections.sort(taskList, new PinnedComparator());
			break;
		default:
			assert false;
		}
	}
	
	private boolean isValidRealIndex(int realIndex) {
		return (realIndex >= 0) && (realIndex < taskList.size());
	}
	
	public boolean isValidViewIndex(int viewIndex) {
		return viewIndex > 0 && viewIndex <= NUM_TASKS_PER_PAGE &&
				isValidRealIndex(convertToRealIndex(viewIndex));
	}

	private int convertToRealIndex(int viewIndex) {
		int realIndex = (currentPage - 1) * NUM_TASKS_PER_PAGE + viewIndex - 1;
		log.trace(String.format(TRACE_REAL_INDEX, realIndex));
		return realIndex;
	}
	
	private int convertToViewIndex(int realIndex) {
		currentPage = realIndex/NUM_TASKS_PER_PAGE + 1;
		return realIndex % NUM_TASKS_PER_PAGE + 1;
	}

	public Task getTask(int viewIndex) {
		if (!isValidViewIndex(viewIndex)) {
			throw new IndexOutOfBoundsException();
		}
		return this.taskList.get(convertToRealIndex(viewIndex));
	}

	public int getNumTotalPages() {
		return this.totalPages;
	}

	public int getCurrentPageNum() {
		return this.currentPage;
	}

	public int getNumTotalTasks() {
		return this.taskList.size();
	}

	public List<Task> getListCurrentPage() {
		taskListCurrentPage = new ArrayList<Task>(NUM_TASKS_PER_PAGE);
		int startInd = (currentPage - 1) * NUM_TASKS_PER_PAGE;
		int offset = computeRealEndIndexOffsetCurrentPage();
		for (int i = 0 ; i <= offset ; i++) {
			taskListCurrentPage.add(taskList.get(startInd + i));
		}
		return taskListCurrentPage;
	}
	
	public ViewListStatus getStatus() {
		return this.status;
	}

	private int computeRealEndIndexOffsetCurrentPage() {
		if (taskList.isEmpty()) {
			return NO_ELEM_IN_LIST;
		}
		else {
			if (currentPage == totalPages) {
				return (taskList.size() - 1) % NUM_TASKS_PER_PAGE;
			}
			else {
				return NUM_TASKS_PER_PAGE - 1;
			}
		}
	}

	private int computeTotalPages() {
		if (taskList.isEmpty()) {
			return 1;
		}
		else {
			return (taskList.size() - 1) / NUM_TASKS_PER_PAGE + 1;
		}
	}
	
	public boolean hasPage(int pageNum) {
		return pageNum > 0 && pageNum <= totalPages;
	}
	
	public boolean turnToPage(int pageNum) {
		if (!hasPage(pageNum)) {
			return false;
		}
		else {
			currentPage = pageNum;
			return true;
		}
	}
	
	/**
	 * Turn to the page contains the task of the given taskId
	 * @param taskId
	 * @return	the viewIndex of the highlighted Task,
	 * 			-1 if not found
	 */
	public int highlightTask(UUID taskId) {
		int i = 0;
		ListIterator<Task> iter = taskList.listIterator();
		while (iter.hasNext()) {
			if (iter.next().getTaskId().equals(taskId)) {
				return convertToViewIndex(i) - 1;
			}
			i++;
		}
		return INDEX_NOT_FOUND;
	}
	
	public void setSearchTerm(String searchTerm) {
		this.searchTerm = searchTerm;
	}
	
	public String getSearchTerm() {
		return this.searchTerm;
	}
}
